﻿using System.Collections.Generic;
using Lidgren.Network;
using Server.Global;
using Server.PC;
using System.Threading;
using TheWorldLibrary.Enumeration;

namespace Server.Network
{
    class ServerTcp
    {
        // private constructor
        private ServerTcp() { }

        // singleton accessor
        static ServerTcp _instance;
        public static ServerTcp Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new ServerTcp();
                return _instance;
            }
        }
        private static NetOutgoingMessage _outgoingPacket;

        public bool IsConnected(int index)
        {
            NetConnection tempClient = (NetConnection)NetworkManager.Instance.connectedClients[index];
            if (tempClient == null)
                return false;
            if (tempClient.Status == NetConnectionStatus.Connected)
            {
                return true;
            }

            return false;
        }

        public bool IsPlaying(int index)
        {
            if (Player.Instance.Players[index] != null && Player.Instance.Players[index].Entity.InGame)
            {
                NetConnection tempClient = (NetConnection)NetworkManager.Instance.connectedClients[index];
                if (tempClient.Status == NetConnectionStatus.Connected)
                    return true;
                else
                    return false;
            }

            return false;
        }

        #region Send Messages Methods

        // Method to send data to orginal sender
        public void SendDataTo(int index, NetOutgoingMessage data, NetDeliveryMethod deliveryMethod)
        {
            _outgoingPacket = NetworkManager.Instance.s_Server.CreateMessage(data.LengthBytes);
            _outgoingPacket.Write(data);
            NetworkManager.Instance.s_Server.SendMessage(_outgoingPacket, (NetConnection)NetworkManager.Instance.connectedClients[index], deliveryMethod);

        }

        // Method to send the message to all //
        public void SendDataToAll(NetOutgoingMessage Data)
        {
            for (int LoopI = 0; LoopI <= 100; LoopI++)
            {
                if (IsConnected(LoopI))
                {
                    SendDataTo(LoopI, Data, NetDeliveryMethod.ReliableOrdered);
                }
            }
        }

        // Method to send the message to all but index //
        public void SendDataToAllBut(int Index, NetOutgoingMessage Data)
        {
            for (int LoopI = 0; LoopI <= Constants.MAX_PLAYERS - 1; LoopI++)
            {
                if (Player.Instance.Players[LoopI] != null)
                {
                    if (LoopI != Index)
                    {
                        SendDataTo(LoopI, Data, NetDeliveryMethod.ReliableOrdered);
                    }
                }
            }
        }

        // Method to send the message to map //
        public void SendDataToMap(int mapNum, NetOutgoingMessage Data)
        {
            for (int i = 0; i <= Constants.MAX_PLAYERS - 1; i++)
            {
                if (Player.Instance.Players[i] == null)
                {
                    continue;
                }
                else if (Player.Instance.Players[i].Entity.InGame)
                {
                    if (Player.Instance.GetPlayerMap(i) == mapNum)
                    {
                        SendDataTo(i, Data, NetDeliveryMethod.ReliableOrdered);
                    }
                }
            }
        }

        // Method to send the message to map but index //
        public void SendDataToMapBut(int index, int mapNum, NetOutgoingMessage Data)
        {
            for (int i = 0; i <= Constants.MAX_PLAYERS - 1; i++)
            {
                if (Player.Instance.Players[i].Entity.InGame)
                {
                    if (Player.Instance.GetPlayerMap(index) == mapNum)
                    {
                        if (i != index)
                        {
                            SendDataTo(i, Data, NetDeliveryMethod.ReliableOrdered);
                        }
                    }
                }
            }
        }


        #endregion

        #region Login/Registration/Create Character

        public void SendLoginOk(int index)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SLoginOk);
            tempBuffer.Write(index);
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
            tempBuffer = null;
        }

        public void SendAccountError(int index, string error = "Account Error")
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SAccountError);
            tempBuffer.Write(error);
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
        }

        public void SendRegisterOkay(int index)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SRegisterOk);
            tempBuffer.Write(index);
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
        }

        public void SendCharacterList(int index, List<string> charNames, List<int> sprites)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SSendChar);
            tempBuffer.Write(charNames.Count);
            for (int i = 0; i < charNames.Count; i++)
            {
                tempBuffer.Write(charNames[i]);
                tempBuffer.Write(sprites[i]);
            }
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
        }

        public void SendJoinedGame(int index)
        {
            NetOutgoingMessage tempbuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempbuffer.Write((int)ServerPackets.SInGame);
            tempbuffer.Write(Player.Instance.GetPlayerName(index));
            tempbuffer.Write(Player.Instance.GetPlayerSprite(index));
            tempbuffer.Write((int)Player.Instance.Players[index].Entity.EnitityGender);
            tempbuffer.Write(Player.Instance.GetPlayerX(index));
            tempbuffer.Write(Player.Instance.GetPlayerY(index));
            tempbuffer.Write(Player.Instance.GetPlayerMap(index));
            SendDataTo(index, tempbuffer, NetDeliveryMethod.ReliableOrdered);
        }

        #endregion

        #region Player Data/Movement/Join/Left

        public NetOutgoingMessage SendPlayerData(int index)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SPlayerData);
            tempBuffer.Write(Player.Instance.Players[index].Entity.EntityName);
            tempBuffer.Write(Player.Instance.Players[index].Entity.EntityClass);
            tempBuffer.Write((int)Player.Instance.Players[index].Entity.EnitityGender);
            tempBuffer.Write(Player.Instance.Players[index].Entity.EntitySpriteNum);
            tempBuffer.Write(index);
            return tempBuffer;
        }

        public void SendJoinMap(int index)
        {
            // Send all players on current map to index
            for (int i = 0; i <= Constants.MAX_PLAYERS - 1; i++)
            {
                if (IsPlaying(i))
                {
                    if (i != index)
                    {
                        if (Player.Instance.Players[i].Entity.EntityMap == Player.Instance.Players[index].Entity.EntityMap)
                        {
                            SendDataTo(index, SendPlayerData(i), NetDeliveryMethod.ReliableOrdered);
                            Thread.Sleep(1);
                        }
                    }
                }
            }

            // Send index's player data to everyone on the map including himself
            SendDataToAll(SendPlayerData(index));

        }

        public void SendLeftGame(int index)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SLeft);
            tempBuffer.Write(index);
            SendDataToAllBut(index, tempBuffer);
        }

        public void SendPlayerMovement(int index)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SPlayerMove);
            tempBuffer.Write(index);
            tempBuffer.Write((int)Player.Instance.Players[index].Entity.EntityDir);
            tempBuffer.Write(Player.Instance.Players[index].Sprite.Position.X);
            tempBuffer.Write(Player.Instance.Players[index].Sprite.Position.Y);
            SendDataToAll(tempBuffer);
        }

        public void SendPlayerNewXY(int index)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SPlayerNewXY);
            tempBuffer.Write((int)Player.Instance.Players[index].Sprite.Position.X);
            tempBuffer.Write((int)Player.Instance.Players[index].Sprite.Position.Y);
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
        }

        #endregion

        #region Player/Map/Global/Alert Messages

        public void SendPlayerMsg(int index, string message)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SPlayerMsg);
            tempBuffer.Write(message);
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
        }

        public void SendMapMsg(int index, string text)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SMapMsg);
            tempBuffer.Write(Player.Instance.GetPlayerName(index) + ": " + text);
            SendDataToMap(Player.Instance.GetPlayerMap(index), tempBuffer);
        }

        public void SendAlertMsg(int index, string message)
        {
            NetOutgoingMessage tempBuffer = NetworkManager.Instance.s_Server.CreateMessage();
            tempBuffer.Write((int)ServerPackets.SAlertMsg);
            tempBuffer.Write(message);
            SendDataTo(index, tempBuffer, NetDeliveryMethod.ReliableOrdered);
        }

        #endregion

    }
}
